/*****************************************************************************/
/* File: Renderer.h                                                          */
/* Author: Ozon                                                              */
/*                                                                           */
/* Description:																 */
/*	Class that have direct access to OpenGL device.							 */
/*****************************************************************************/
#pragma once

#include <windows.h>
#include <math.h>

#include <gl/gl.h>
#include <gl/glu.h>
#include <cg/cg.h>
#include <cg/cgGL.h>

#include "DrawList.h"
#include "Level.h"
#include "Camera.h"

#include "Common.h"

class CRenderer
{
private:

	static const int sc_iMaxLights = 10;
	
	HDC m_hDC;
	int m_iGLPixelIndex;	//index of pixel format
	HGLRC m_hGLContext;		//context of Gl device.
	CGcontext m_cgContext;			//context of shader device
	CGprofile m_cgProfVertex;		//hardware profile of vertex shader
 	CGprofile m_cgProfFragment;		//hardware profile of fragment shader

	double3 m_d3LightPos[sc_iMaxLights];	//positions of lights in world
	double3 m_d3LightCol[sc_iMaxLights];	//colors of lights
	bool m_bLightEnabled[sc_iMaxLights];	//on/off states of lights

	double3 m_d3AmbientLight;	//color of ambient light

	double3 m_d3EyePos;		//observator position

	SMaterial m_matCurrent;	//current material

	double m_dMMatrix[16];	//current model matrix
	double m_dVMatrix[16];	//current view matrix
	double m_dPMatrix[16];	//current projection matrix;
	

	unsigned int m_uiWidth;		//width of rendered window
	unsigned int m_uiHeight;	//height of rendered window


private:
	int SetWindowPixelFormat(HDC hDC);
	int CreateViewGLContext(HDC hDC);


public:

	//vertex description
	static const struct SVert{
		float3 f3Pos;
		float3 f3Normal;
		float2 f2TexCoord;

		SVert(float3 f3P, float3 f3N, float2 f2T)
			: f3Pos(f3P), f3Normal(f3N), f2TexCoord(f2T)
		{
		}
		SVert()
		{
		}

		bool operator==(SVert v)
		{
			return (f3Pos==v.f3Pos)&&(f3Normal==v.f3Normal)&&(f2TexCoord==v.f2TexCoord);
		}
	};

	

	CRenderer(HDC hDC, unsigned int uiWidth, unsigned int uiHeight);
	~CRenderer(void);

	int Init();
	int Destroy();

	void InitProfiles();

	unsigned int GetWidth(){return m_uiWidth;}
	unsigned int GetHeight(){return m_uiHeight;}
	CGcontext GetCGContext() { return m_cgContext; }

	CGprogram CompileVertexShader(const char* szFileName);
	CGprogram CompileFragmentShader(const char* szFileName);

	void CGErrorNotify();

	void BindVertexProgram(CGprogram cgProg);
	void BindFragmentProgram(CGprogram cgProg);
	void DisableVertex();
	void DisableFragment();

	void BindPrograms(CGprogram cgProgVertex, CGprogram cgProgFragment);
	void DisableShaders();

	//sets current material
	void SetMaterial(SMaterial matCurrent) { m_matCurrent = matCurrent; }

	//sets observator position
	void SetEyePosition(double3 d3EyePos) { m_d3EyePos = d3EyePos; }

	//sets ambient color
	void SetAmbientLight(double3 d3LightCol) { m_d3AmbientLight = d3LightCol; }

	//get current matrices from opengl:
	void FetchProjectionMatrix();
	void FetchViewMatrix();

	//setup user-model matrix:
	void SetModelMatrix(double dMMatrix[16]);

	//send one double3 parameter to shader program
	void SetShaderParamd3(CGprogram cgProg, const char* szParamName, double3 d3Param);
	//send one double parameter to shader program
	void SetShaderParamd(CGprogram cgProg, const char* szParamName, double dParam);
	//send material information to shader program
	void SetShaderMaterialParams(CGprogram cgProg);
	//send light params to gl program
	void SetShaderLightParams(CGprogram cgProg, double dIMMatrix[16]);
	//send gl parameters to shaders
	void SetShaderParams(CGprogram cgProgVertex, CGprogram cgProgFragment);
	//send texture parameter
	void SetTextureParamui(CGprogram cgProgFragment, const char* szParamName, unsigned int uiTexName);
	//enables or disables user texture management
	void CRenderer::ManageTexParams(bool bEnabled);

	int Draw();

};
